/////////////////////////////////////////////////////////////////////////////
// Name:        ax_resource.cpp
// Purpose:     Accessibility classes: AxResource
// Author:      Julian Smart
// Modified by:
// Created:     2009-03-20
// RCS-ID:
// Copyright:   (c) Julian Smart
// Licence:     New BSD License
/////////////////////////////////////////////////////////////////////////////

#include "wx/wx.h"

#include "wx/filename.h"

#include "ax/ax_utils.h"
#include "ax_resource/ax_resource.h"
#include "variantutils/variantstream.h"

/*!
 * AxResource class declaration
 * A resource can represent a tool, document, file, web site, etc.
 */

IMPLEMENT_CLASS( AxResource, AxDocument )

// WX_DEFINE_OBJARRAY(AxResourceArray)

AxResource::~AxResource()
{
    ClearChildren();
}

void AxResource::Init()
{
    m_localFile = true;
}

/// Copy the basic resource information.
void AxResource::Copy(const AxResource& resource)
{
    AxDocument::Copy(resource);

    m_properties = resource.m_properties;
    m_localFile = resource.m_localFile;
}

/// Test equality for the basic resource information
bool AxResource::Eq(const AxResource& resource) const
{
    return (/* m_properties == resource.m_properties && */ m_modified == resource.m_modified && m_localFile == resource.m_localFile);
}


/// Read public properties, always the first part of the record
bool AxResource::ReadProperties(wxDataStreamHelper& helper)
{
    wxVariant attr;
    while (helper.Read(attr))
    {
        wxString name(attr.GetName());
        if (name == wxT("is-local-file"))
            m_localFile = attr.GetBool();
        else
            SetProperty(attr);

        attr = wxVariant();
    }
    return true;
}

/// Write public properties, always the first part of the record
bool AxResource::WriteProperties(wxDataStreamHelper& helper)
{
    size_t i;
    for (i = 0; i < (size_t) GetPropertyCount(); i++)
    {
        helper.Write(GetPropertyPtr(i)->GetVariant());
    }
    helper.Write(m_localFile, wxT("is-local-file"));
    helper.WriteEnd();
    return true;
}

/// Read children
bool AxResource::ReadChildren(wxDataStreamHelper& helper)
{
    int childCount = 0;
    wxVariant attr;
    while (helper.Read(attr))
    {
        if (attr.GetName() == wxT("child-count"))
            childCount = (int) attr.GetLong();
    }
    int i;
    for (i = 0; i < childCount; i++)
    {
        wxString className;
        wxVariant attr2;
        while (helper.Read(attr2))
        {
            if (attr2.GetName() == wxT("class-name"))
                className = attr2.GetString();
        }
        if (!className.IsEmpty())
        {
            wxObject* obj = wxCreateDynamicObject(className);
            if (!obj)
                return false;

            AxResource* resource = wxDynamicCast(obj, AxResource);
            if (!resource)
            {
                delete obj;
                return false;
            }
            if (resource)
            {
                resource->Read(helper);
                AddChild(resource);
            }
        }
    }

    return true;
}

/// Write children
bool AxResource::WriteChildren(wxDataStreamHelper& helper)
{
    helper.Write((int) m_children.GetCount(), wxT("child-count"));
    helper.WriteEnd();

    size_t i;
    for (i = 0; i < m_children.GetCount(); i++)
    {
        AxResource* child = GetChild(i);
        if (child)
        {
            helper.Write(wxString(child->GetClassInfo()->GetClassName()), wxT("class-name"));
            helper.WriteEnd();

            child->Write(helper);
        }
    }
    
    return true;
}


/// Read the data for this resource. By default, this simply reads
/// the properties and children. Override this function to read other data.
bool AxResource::Read(wxDataStreamHelper& helper)
{
    ReadProperties(helper);
    ReadChildren(helper);
    return true;
}

/// Write the data for this resource. By default, this simply writes
/// the properties and children. Override this function to write other data.
bool AxResource::Write(wxDataStreamHelper& helper)
{
    WriteProperties(helper);
    WriteChildren(helper);
    return true;
}

/// Set a property
void AxResource::SetProperty(const AxProperty& property)
{
    m_properties.SetProperty(property);
}

void AxResource::SetProperty(const wxString& name, const wxString& value)
{
    m_properties.SetProperty(name, value);
}

void AxResource::SetProperty(const wxString& name, const wxString& value, const wxArrayString& choices)
{
    m_properties.SetProperty(name, value);
    AxProperty* prop = m_properties.FindProperty(name);
    prop->SetChoices(choices);
}

void AxResource::SetProperty(const wxString& name, long value)
{
    m_properties.SetProperty(name, value);
}

void AxResource::SetProperty(const wxString& name, int value)
{
    m_properties.SetProperty(name, (long) value);
}

void AxResource::SetProperty(const wxString& name, bool value)
{
    m_properties.SetProperty(name, value);
}

void AxResource::SetProperty(const wxVariant& value)
{
    m_properties.SetProperty(value.GetName(), value);
}

/// Get a property
AxProperty AxResource::GetProperty(const wxString& name) const
{
    AxProperty* prop = m_properties.FindProperty(name);
    if (prop)
        return *prop;
    else
        return AxProperty();
}

/// Get a property value variant
wxVariant AxResource::GetPropertyValue(const wxString& name) const
{
    return m_properties.FindPropertyValue(name);
}

/// Get a string property value
wxString AxResource::GetPropertyString(const wxString& name) const
{
    return m_properties.FindPropertyValueString(name);
}

/// Get a long property value
long AxResource::GetPropertyLong(const wxString& name) const
{
    return m_properties.FindPropertyValueLong(name);
}

/// Get a double property value
double AxResource::GetPropertyDouble(const wxString& name) const
{
    return m_properties.FindPropertyValueDouble(name);
}

/// Get a bool property value
long AxResource::GetPropertyBool(const wxString& name) const
{
    return m_properties.FindPropertyValueBool(name);
}

/// Does this property exist?
bool AxResource::HasProperty(const wxString& name) const
{
    return m_properties.FindProperty(name) != NULL;
}

/// Get current properties - doesn't necessarily mean they're all supported
wxArrayString AxResource::EnumerateProperties() const
{
    wxArrayString props;
    size_t i;
    for (i = 0; i < m_properties.GetCount(); i++)
        props.Add(m_properties.GetProperty(i)->GetName());
    return props;
}

AxProperty AxResource::GetProperty(size_t i) const
{
    AxProperty* prop = m_properties.GetProperty(i);
    if (prop)
        return *prop;
    else
        return AxProperty();
}

/// Clear children
void AxResource::ClearChildren()
{
    while (GetChildren().GetCount() > 0)
    {
        AxResource* resource = GetChildren()[0];
        GetChildren().RemoveAt(0);
        if (resource)
            delete resource;
    }
}

/// Add child
bool AxResource::AddChild(AxResource* resource)
{
    m_children.Add(resource);
    return true;
}

/// Remove child
bool AxResource::RemoveChild(AxResource* resource)
{
    size_t i;
    for (i = 0;i < GetChildren().GetCount(); i++)
    {
        AxResource* r = GetChildren()[i];
        if (r == resource)
        {
            GetChildren().RemoveAt(i);
            return true;
        }
    }
    return false;
}

/// Find by filename (look at this object, and children).
AxResource* AxResource::FindByFilename(const wxString& filename) const
{
#ifdef __WXMSW__
    wxString f1(GetFilename().Lower());
    wxString f2(filename.Lower());
#else
    wxString f1(GetFilename());
    wxString f2(filename);
#endif

    if (f1 == f2)
        return (AxResource*) this;

    size_t i;
    for (i = 0;i < GetChildren().GetCount(); i++)
    {
        AxResource* r = GetChildren()[i];
        if (r->FindByFilename(filename))
            return r;
    }

    return false;
}
